<?php

namespace App\Services\Payment\Sumpay;

use App\Services\Payment\Sumpay\AesServer;

class Sumpay
{
    private $url = env('SUMPAY_URL');

    public static function do_post_multipart_request($url, $data, $file_fields = null, $optional_headers = null)
    {
        $cURLHandle = curl_init($url);
        if($file_fields != null)
        {
            foreach ($file_fields as $key => $value)
            {
                $data[$key] = $value;
            }
        }
    //     curl_setopt ($cURLHandle, CURLOPT_SSL_VERIFYPEER, 1);
    //     curl_setopt ($cURLHandle, CURLOPT_SSL_VERIFYHOST, 2);
    //     curl_setopt ($cURLHandle, CURLOPT_FOLLOWLOCATION, TRUE);
        curl_setopt($cURLHandle, CURLOPT_POST,true);
        curl_setopt($cURLHandle, CURLOPT_POSTFIELDS, $data);
        curl_setopt($cURLHandle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        //设置头文件的信息作为数据流输出
    //     curl_setopt($cURLHandle, CURLOPT_HEADER, 0);
        //设置获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($cURLHandle, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($cURLHandle, CURLOPT_HTTPHEADER, $optional_headers);
        $result = curl_exec($cURLHandle);
        $php_errormsg = null;
        if (curl_errno($cURLHandle))
        {
            $php_errormsg = curl_error($cURLHandle);
        }

        curl_close ($cURLHandle);
        if ($php_errormsg != null)
        {
            throw new Exception ( "Problem reading data from $url, $php_errormsg" );
        }

        $obj = json_decode($result, TRUE);
        $signature = $obj['sign'];
        $obj['sign'] = '';
        $obj['sign_type'] = '';
        $data = self::getStr($obj);
        $re = self::verify($data, $signature, 'cer/dev_pub.pem');
        if($re)
        {
            return $obj;
        }
        return json_decode("{'resp_code':'888888','resp_msg':'验签失败'}", TRUE);
    }

    public static function do_post_request($url, $data, $optional_headers = null)
    {
        $cURLHandle = curl_init($url);
        //     curl_setopt ($cURLHandle, CURLOPT_SSL_VERIFYPEER, 1);
        //     curl_setopt ($cURLHandle, CURLOPT_SSL_VERIFYHOST, 2);
        //     curl_setopt ($cURLHandle, CURLOPT_FOLLOWLOCATION, TRUE);
        curl_setopt($cURLHandle, CURLOPT_POST,true);
        curl_setopt($cURLHandle, CURLOPT_POSTFIELDS, $data);
        curl_setopt($cURLHandle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
        //设置头文件的信息作为数据流输出
        //     curl_setopt($cURLHandle, CURLOPT_HEADER, 0);
        //设置获取的信息以文件流的形式返回，而不是直接输出。
        curl_setopt($cURLHandle, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($cURLHandle, CURLOPT_HTTPHEADER, $optional_headers);
        $result = curl_exec($cURLHandle);
        var_dump($url, $data, $result);//此处打印返回值 类型，长度，值。商户自行选择是否打印
        $php_errormsg = null;
        if (curl_errno($cURLHandle))
        {
            $php_errormsg= curl_error($cURLHandle);
        }
        curl_close ($cURLHandle);
        if ($php_errormsg != null)
        {
            throw new Exception ( "Problem reading data from $url, $php_errormsg" );
        }
        $obj = json_decode($result, TRUE);
        // dd($result, $obj);
        $signature = $obj['sign'] ?? '';
        $obj['sign'] = '';
        $obj['sign_type'] = '';
        $data = self::getStr($obj);
        // $pem_file = "/Users/fuxiudong/data/httpd/work_php81/enzhongfu/manager/app/Services/Payment/Sumpay/cer/dev_pub.pem";
        // $pem_file = "/www/wwwroot/manager.ezfclouds.com/manager/manager/app/Services/Payment/Sumpay/cer/dev_pub.pem";
        $pem_file = env('SUMPAY_PEM_FILE');
        $re = self::verify($data, $signature, $pem_file);
        if($re)
        {
            return $obj;
        }
        return json_decode("{'resp_code':'888888','resp_msg':'验签失败'}", TRUE);
    }

    public static function execute($url, $charset, $data, $privateKeyName, $password, $publicKeyName, $domain, $charset_change_fields, $encrypted_fields, $special_fields, $json_array_fields, $defaultCharset)
    {

        $aes = new AesServer();

        $aesKey = $aes->getAesKey();
        // dd($aesKey);
        $aes->set_key($aesKey);
        $aes->require_pkcs5();
        $data = self::processJSONArrayFields($data, $charset, $charset_change_fields, $encrypted_fields, $special_fields, $json_array_fields, $defaultCharset, $aes);
        $data = self::charsetChange($charset_change_fields, $data, $charset, $defaultCharset);
        $data = self::encryptByAesKey($encrypted_fields, $data, $aes);
        // dd($aesKey,$publicKeyName);
        $aesKey = self::encrpyt(base64_encode($aesKey), $publicKeyName);
        $data['aes_key'] = $aesKey;
        $data = self::specialChange($special_fields, $data);
        $signStr = self::sign(self::getStr($data), $privateKeyName, $password);
        // dd($data, self::getStr($data),$privateKeyName, $password,$signStr);
        $data['sign'] = $signStr;
        $data['sign_type'] = 'CERT';
        $optional_headers =  Array("Referer: " . $domain);
        return self::do_post_request($url, $data, $optional_headers);
    }

    public static function processJSONObjectFields($data, $charset, $charset_change_fields, $encrypted_fields, $special_fields, $json_fields, $defaultCharset, $aes){
        foreach ($json_fields as $key)
        {
            if (isset($data[$key]))
            {
                $json_obejct = json_decode($data[$key], TRUE);
                $json_obejct= self::charsetChange($charset_change_fields, $json_obejct, $charset, $defaultCharset);
                $json_obejct= self::encryptByAesKey($encrypted_fields, $json_obejct, $aes);
                $json_obejct= self::specialChange($special_fields, $json_obejct);
                $data[$key] = self::json_encode($json_obejct);
            }
        }
        return $data;
    }

    public static function processJSONArrayFields($data, $charset, $charset_change_fields, $encrypted_fields, $special_fields, $json_array_fields, $defaultCharset, $aes){
        foreach ($json_array_fields as $key)
        {
            if (isset($data[$key]))
            {
                $json_array = json_decode($data[$key], TRUE);
                for($i=0;$i<count($json_array);$i++)
                {
                    $json_obejct = $json_array[$i];
                    $json_obejct = self::charsetChange($charset_change_fields, $json_obejct, $charset, $defaultCharset);
                    $json_obejct = self::encryptByAesKey($encrypted_fields, $json_obejct, $aes);
                    $json_obejct = self::specialChange($special_fields, $json_obejct);
                    $json_array[$i] = $json_obejct;
                }
                $data[$key] = json_encode($json_array);
            }
        }
        // dd($data);
        return $data;
    }

    public static function charsetChange($charset_change_fields, $data, $merCharset, $defaultCharset)
    {
        if($defaultCharset == $merCharset)
        {
            return $data;
        }

        foreach ($charset_change_fields as $key)
        {
            if (isset($data[$key]))
            {
                $value = $data[$key];
                if ($value && "" != $value)
                {
                    $data[$key] = iconv($merCharset, $defaultCharset, $value);
                }
            }
        }
        return $data;
    }

    public static function encryptByAesKey($encrypted_fields, $data, $aes)
    {
        foreach ($encrypted_fields as $key)
        {
            if (isset($data[$key]))
            {
                $value = $data[$key];
                if ($value && "" != $value)
                {
                    if(phpversion() >= 7.1)
                    {
                        $data[$key] = $aes->aes_encode($value);
                    }
                    else
                    {
                        $data[$key] = $aes->encrypt($value);
                    }
                }
            }
        }
        return $data;
    }

    public static function specialChange($special_fields, $data)
    {
        foreach ($special_fields as $key)
        {
            if (isset($data[$key]))
            {
                $value = $data[$key];
                if ($value && "" != $value)
                {
                    $data[$key] = base64_encode($value);
                }
            }
        }
        return $data;
    }


    public static function sign($data, $privateKeyPath, $password)
    {
        $certs = array();
        $res = openssl_pkcs12_read(file_get_contents($privateKeyPath), $certs, $password);
        // dd('aa',$privateKeyPath, $password, file_get_contents($privateKeyPath), $certs, $res);
        if(!$certs)
        {
            return;
        }
        $signature = '';
        openssl_sign($data, $signature, $certs['pkey'], 'sha256');
        return base64_encode($signature);
    }

    public static function verify($data, $signature, $publicKeyName)
    {
        $result = (bool)openssl_verify($data, base64_decode($signature), file_get_contents($publicKeyName), 'sha256');
        return $result;
    }

    public static function encrpyt($data, $publicKeyName)
    {
        openssl_public_encrypt($data,$encrypted,file_get_contents($publicKeyName));//公钥加密
        return base64_encode($encrypted);
    }

    public static function getStr($parameters)
    {
        $func = function($v)
        {
           return $v != '' || $v == '0';
        };
        // $parameters = array_filter($parameters,create_function('$v','return $v != \'\' || $v == \'0\';'));
        $parameters = array_filter($parameters, $func);
        $needSign = '';
        $first = true;
        ksort($parameters);
        foreach (array_keys($parameters) as $key)
        {
            if($first){
                $first = false;
            }else{
                $needSign .= "&";
            }
            $needSign .= $key;
            $needSign .= "=";
            $needSign .= $parameters[$key];
        }

        return $needSign;
    }
}

?>